package com.mlog.njyjy.ndop.share.zabbix.response;

import com.google.gson.*;
import com.mlog.njyjy.ndop.share.zabbix.ex.ZabbixClientException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * response
 * </p>
 *
 * @author <a href="mailto:yingxiufeng@mlogcn.com">alex</a>
 * @version v1.0, 2020/6/29
 */
public class ZabbixResponse {

    private static final Logger log = LoggerFactory.getLogger(ZabbixResponse.class);

    private static final String RESULT = "result";

    private Gson gson;

    /**
     * 请求响应 code eg 200/500
     */
    private int responseCode;

    /**
     * 原样返回
     */
    private String jsonrpc;

    /**
     * 请求的id
     */
    private Integer id;

    /**
     * error 对象
     */
    private ZabbixResponseError error;

    /**
     * error code
     */
    private int errorCode = 0;

    /**
     * error message
     */
    private String errorMessage;

    /**
     * 接口响应 string
     */
    private String jsonString;

    /**
     * 接口响应 对象
     */
    private JsonObject jsonObject;


    public ZabbixResponse(Gson gson) {
        this.gson = gson;
    }

    /**
     * is succeeded or not
     *
     * @return
     */
    public boolean isSucceeded() {
        return isHttpSuccessful() && Objects.isNull(error);
    }

    /**
     * 错误码
     *
     * @return
     */
    public int getErrorCode() {
        return Objects.isNull(error) ? errorCode : error.getCode();
    }

    /**
     * 错误消息
     *
     * @return
     */
    public String getErrorMessage() {
        return Objects.isNull(error) ? errorMessage : error.getMessage() + ":" + error.getData();
    }

    /**
     * 接口 error
     *
     * @return
     */
    public ZabbixResponseError getError() {
        return error;
    }

    /**
     * 响应结果的 result 部分
     *
     * @param type
     * @param <T>
     * @return
     */
    public <T> T getResultAsObject(Class<T> type) {
        if (isSucceeded()) {
            JsonElement jsonElement = jsonObject.get(RESULT);
            if (jsonElement.isJsonPrimitive()) {
                return (T) getPrimitiveValue(jsonElement.getAsJsonPrimitive(), type);
            } else if (jsonElement.isJsonObject()) {
                String json = jsonElement.getAsJsonObject().toString();
                return gson.fromJson(json, type);
            } else if (jsonElement.isJsonArray()) {
                //return first one
                List<T> list = getResultAsObjectList(type);
                if (list.size() > 0) {
                    return list.get(0);
                }
            }
        } else {
            throw new ZabbixClientException("[zabbix client] get result error: " + getErrorMessage());
        }
        return null;
    }

    /**
     * get result list
     * @param type
     * @param <T>
     * @return
     */
    public <T> List<T> getResultAsObjectList(Class<T> type) {
        List<T> objectList = new ArrayList<>();
        if (isSucceeded()) {
            JsonElement jsonElement = jsonObject.get(RESULT);
            if (jsonElement.isJsonArray()) {
                for (JsonElement source : jsonElement.getAsJsonArray()) {
                    T obj = gson.fromJson(source.getAsJsonObject(), type);
                    if (obj != null) {
                        objectList.add(obj);
                    }
                }
            } else {
                throw new ZabbixClientException("[zabbix client] get result list error: the result is not an array ");
            }
        }
        return objectList;
    }

    public String getJsonString() {
        return jsonString;
    }

    public JsonObject getJsonObject() {
        return jsonObject;
    }

    //region ========set==========

    public void setResponseCode(int responseCode) {
        this.responseCode = responseCode;
    }

    public void setJsonrpc(String jsonrpc) {
        this.jsonrpc = jsonrpc;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setError(ZabbixResponseError error) {
        this.error = error;
    }

    public void setErrorCode(int errorCode) {
        this.errorCode = errorCode;
    }

    public void setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
    }

    public void setJsonString(String jsonString) {
        this.jsonString = jsonString;
    }

    public void setJsonObject(JsonObject jsonObject) {
        this.jsonObject = jsonObject;
    }

    private boolean isHttpSuccessful() {
        return (this.responseCode / 100) == 2;
    }
    //endregion

    private Object getPrimitiveValue(JsonPrimitive jsonPrimitive, Class<?> type) {
        if (String.class.equals(type) || Character.class.equals(type)) {
            return jsonPrimitive.getAsString();
        } else if (Boolean.class.equals(type) || boolean.class.equals(type)) {
            return jsonPrimitive.getAsBoolean();
        } else if (Double.class.equals(type) || double.class.equals(type)) {
            return jsonPrimitive.getAsDouble();
        } else if (BigDecimal.class.equals(type)) {
            return jsonPrimitive.getAsBigDecimal();
        } else if (Float.class.equals(type) || float.class.equals(type)) {
            return jsonPrimitive.getAsFloat();
        } else if (Integer.class.equals(type) || int.class.equals(type)) {
            return jsonPrimitive.getAsInt();
        } else if (Long.class.equals(type) || long.class.equals(type)) {
            return jsonPrimitive.getAsLong();
        } else {
            log.warn("[zabbix client] 类型 [{}] 不支持自动转换, 将返回默认字符串值", type.getSimpleName());
            return jsonPrimitive.getAsString();
        }
    }
}
